/* $Id: AbstractEntry.java 137 2011-08-29 20:33:36Z altdotua@gmail.com $ */

package alt.djudge.frontend.server.datatypes;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.Map;

import javax.jdo.PersistenceManager;
import javax.jdo.Transaction;
import javax.jdo.annotations.Persistent;

import alt.djudge.frontend.server.Deployment;
import alt.djudge.frontend.server.HibernateUtil;
import alt.djudge.frontend.server.PMF;
import alt.djudge.frontend.shared.dto.admin.AdminDTOEntry;


public abstract class AbstractEntry implements Serializable
{
	private static final long serialVersionUID = 1L;
	
	//private static final Logger log = Logger.getLogger(AbstractEntry.class);
	
	/* Id - primary key */
	public abstract Long getId();
	
	public abstract void setId(Long id);
	
	// is active
	@Persistent
	protected Boolean active = true;

	// public visibility
	@Persistent
	protected Boolean visible = false;

	// create time
	@Persistent
	protected Date createTime = new Date();
	
	// update time
	@Persistent
	protected Date updateTime = new Date();	
	
	@Persistent
	private Boolean deleted = false;
	
	public AbstractEntry()
	{
		setId(null);
	}
	
	public String getServletPath()
	{
		return (this.getClass().getSimpleName().toLowerCase().split("entry")[0]) + "s";
	}
	
	public boolean isDataFieldName(String name)
	{
		if (name.startsWith("jdo") || name.equals("serialVersionUID"))
			return false;
		return true;
	}
	
	/* Visible - show record? */
	final public Boolean getVisible()
	{
		return visible;
	}
	
	final public void setVisible(Boolean fVisible)
	{
		visible = fVisible;
	}
	
	/* Active - take record into account? */
	final public Boolean getActive()
	{
		return active;
	}
	
	final public void setActive(Boolean fActive)
	{
		active = fActive;
	}
	
	/* CreateTime - time when the record was created */
	final public void setCreateTime(Date date)
	{
		createTime = date;
	}
	
	final public Date getCreateTime()
	{
		return createTime;
	}
	
	/* UpdateTime - time when the record was last updated */
	final public void setUpdateTime(Date date)
	{
		updateTime = date;
	}
	
	final public Date getUpdateTime()
	{
		return updateTime;
	}
	
	protected void clearCacheCustom()
	{
		
	}
	
	protected void clearCache()
	{
		// FIXME: 
		/*Cache cache = CacheModel.getStaticCache();
	    String keyById = CacheModel.getEntryByIdKey(this.getClass(), getId());
		String keyMap = CacheModel.getEntriesMapKey(this.getClass());
		String keyAll = CacheModel.getEntriesAllKey(this.getClass());
		String keyAllActive = CacheModel.getEntriesAllActiveKey(this.getClass());
	    cache.remove(keyById);
	    cache.remove(keyMap);
	    cache.remove(keyAll);
	    cache.remove(keyAllActive);
	    clearCacheCustom();*/
	}
	
	public boolean makePersistent()
	{
		// Setting create time (if object is new)
		if (getCreateTime() == null)
			createTime = new Date();
		// Setting last update time
		this.updateTime = new Date();
		if (Deployment.isGAE())
		{
    		PersistenceManager pm = PMF.get().getPersistenceManager();
    		Transaction tx = pm.currentTransaction();
    		try
    		{
    			System.out.println("making persistent " + this.getClass() + "#" + getId());
    		    tx.begin();
    		    pm.makePersistent(this);
    		    tx.commit();
    		}
    		catch (Exception e)
    		{
    			System.out.println("makePersistent failed");
    			e.printStackTrace();
    			return false;
    		}
    		finally
    		{
    			if (tx.isActive())
    			{
    				tx.rollback();
    			}
    		}
		}
		else
		{
			HibernateUtil.saveOrUpdateObject(this);
		}
		return true;
	}
	
	/**
	 * Permanently deletes an object
	 */
	public boolean deletePersistent()
	{
		if (Deployment.isGAE())
		{
    		PersistenceManager pm = PMF.get().getPersistenceManager();
    		Transaction tx = pm.currentTransaction();
    		try
    		{
    		    tx.begin();
    		    pm.deletePersistent(this);
    		    tx.commit();
    		}
    		catch (Exception e)
    		{
    			//log.warn("deletePersistent failed", e);
    			return false;
    		}
    		finally
    		{
    			if (tx.isActive())
    			{
    				tx.rollback();
    			}
    		}
    		return true;
		}
		else
		{
			return HibernateUtil.deleteObject(this);
		}
	}
	
	/**
	 * Marks object as `deleted' 
	 */
	public boolean delete()
	{
		setDeleted(true);
		makePersistent();
		return true;
	}
	
	
	public void setValues(Map<String, Object> map)
	{
		
	}
	
	public Object getFieldValue(Field field)
	{
		try
		{
			String methodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
			return this.getClass().getMethod(methodName).invoke(this, new Object[0]);
		}
		catch (Exception e)
		{
			//log.warn("getFieldValue failed", e);
		}
		return "'!!!Error!!!'";
	}
	
	public long getSerialVersionUID()
	{
		return serialVersionUID;
	}

	public void setDeleted(Boolean deleted)
	{
		this.deleted = deleted;
	}

	public Boolean getDeleted()
	{
		return deleted;
	}
	
	public void fromDTO(AdminDTOEntry dtoEntry)
	{
		System.out.println(this.getClass() + " fromDTO not implemented");
	}

	public AdminDTOEntry ownAdminDTO()
	{
		System.out.println("!!! Not implemented");
		return null;
	}
	
	protected void appentAdminCommonDTO(AdminDTOEntry entry)
	{
		entry.setActive(getActive());
		entry.setVisible(getVisible());
		entry.setDeleted(getDeleted());
		entry.setCreateTime(getCreateTime());
		entry.setUpdateTime(getUpdateTime());
		entry.setId(getId());
	}
	
	public AdminDTOEntry asAdminDTO()
	{
		AdminDTOEntry entry = ownAdminDTO();
		appentAdminCommonDTO(entry);
		return entry;
	}
}
